﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Threading;
using System.Xml.Linq;
using NthDownload.Composition;
using NthDownload.Contracts;

namespace NthDownload.DownloadPlugins.Http.Serialization
{
    public class HttpSettingsXmlSerializationService : ISerializationService<HttpSettings, string>
    {
        #region Constructor

        public HttpSettingsXmlSerializationService()
        {
            ImportService.TrySatisfyImports(this);
        }

        #endregion Constructor

        #region Properties

        /// <summary>
        /// The Synchronization Context of the executing thread
        /// </summary>
        [Import(typeof(SynchronizationContext), AllowRecomposition = true)]
        public SynchronizationContext UISynchronizationContext { get; set; }

        #endregion Properties

        #region Methods

        public string Serialize(HttpSettings obj)
        {
            if (obj == null)
            {
                throw new Exception("Can't serialize null http settings.");
            }

            //
            // Build XML
            //
            XElement rootElement = new XElement("HttpSettings");
            rootElement.SetAttributeValue("DefaultDestinationPath", obj.DefaultDestinationPath);

            XElement credentialsElement = new XElement("Credentials");
            rootElement.Add(credentialsElement);

            foreach (var credential in obj.Credentials)
            {
                XElement credentialElement = new XElement("Credential");
                
                credentialElement.SetAttributeValue("Domain", credential.Domain);
                credentialElement.SetAttributeValue("Username", credential.Username);
                credentialElement.SetAttributeValue("Password", credential.Password);
                
                credentialsElement.Add(credentialElement);
            }

            return rootElement.ToString();
        }
        //TODO Encrypt password when persisting
        public HttpSettings Deserialize(string data)
        {
            //
            // Read data from element tree
            //
            HttpSettings settings = null;
            UISynchronizationContext.Send(state => settings = new HttpSettings(), null);
            if (settings == null)
            {
                throw new Exception("Http settings initialization failed.");
            }

            Deserialize(data, settings);

            return settings;
        }

        public void Deserialize(string data, HttpSettings obj)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }

            HttpSettings settings = obj;


            //
            // Parse data into element tree
            //
            XElement rootElement = XElement.Parse(data);

            IEnumerable<XElement> credentials = rootElement.Descendants("Credential");

            foreach (XElement credentialElement in credentials)
            {
                HttpCredentials HttpCredentials = new HttpCredentials();

                HttpCredentials.Domain = (string)credentialElement.Attribute("Domain") ?? "";
                HttpCredentials.Username = (string)credentialElement.Attribute("Username") ?? "";
                HttpCredentials.Password = (string)credentialElement.Attribute("Password") ?? "";

                obj.Credentials.Add(HttpCredentials);
            }

            settings.DefaultDestinationPath = (string)rootElement.Attribute("DefaultDestinationPath") ?? "";
        }

        #endregion Methods
    }
}
